package com.atguigu.tingshu.payment.service.impl;

import com.atguigu.tingshu.account.client.RechargeInfoFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.account.RechargeInfo;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private RSAAutoCertificateConfig config;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private RechargeInfoFeignClient rechargeInfoFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Override
    public Transaction wxNotify(HttpServletRequest request) {
        //  获取签名参数：
        String wechatSignature = request.getHeader("Wechatpay-Signature");
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");
        String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
        String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
        //  获取请求主体：
        String requestBody = PayUtil.readData(request);
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(wechatpayNonce)
                .signature(wechatSignature)
                .timestamp(wechatTimestamp)
                .body(requestBody)
                .build();

        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);
        try {
            // 以支付通知回调为例，验签、解密并转换成 Transaction
            Transaction transaction = parser.parse(requestParam, Transaction.class);
            //  返回数据
            return transaction;
        } catch (ValidationException e) {
            // 签名验证失败，返回 401 UNAUTHORIZED 状态码
           throw new RuntimeException("签名验证失败");
        }
    }

    @Override
    public void updatePaymentInfoStatus(Transaction transaction) {
        //	更新交易状态：
        //	先获取 paymentInfo 对象；
        PaymentInfo paymentInfo = paymentInfoService.getOne(new LambdaQueryWrapper<PaymentInfo>().eq(PaymentInfo::getOrderNo, transaction.getOutTradeNo()));
        //	判断
        if (null != paymentInfo && SystemConstant.PAYMENT_STATUS_PAID.equals(paymentInfo.getPaymentStatus())) {
            //	已支付；更新了状态;
            return;
        }
        //	更新交易记录状态;
        paymentInfo.setPaymentStatus(SystemConstant.PAYMENT_STATUS_PAID);
        //	更新一个微信支付内部的交易号;
        paymentInfo.setOutTradeNo(transaction.getTransactionId());
        paymentInfo.setCallbackTime(new Date());
        paymentInfo.setCallbackContent(transaction.toString());
        paymentInfoService.updateById(paymentInfo);

        //	更新订单状态或充值状态;
        String routingKey = paymentInfo.getPaymentType().equals(SystemConstant.PAYMENT_TYPE_ORDER) ? MqConst.ROUTING_ORDER_PAY_SUCCESS : MqConst.ROUTING_RECHARGE_PAY_SUCCESS;
        //  发送消息更新支付状态;
        rabbitService.sendMessage(MqConst.EXCHANGE_ORDER,routingKey,paymentInfo.getOrderNo());
    }

    @Override
    public Transaction queryPayStatus(String orderNo) {
        //	创建对象
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayV3Config.getMerchantId());
        queryRequest.setOutTradeNo(orderNo);

        try {
            //	创建servie 对象;
            JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
            Transaction result = service.queryOrderByOutTradeNo(queryRequest);
            System.out.println(result.getTradeState());
            //	返回数据
            return result;
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
        }
        return null;
    }

    @Override
    public Map<String, Object> createJsapi(String paymentType, String orderNo, Long userId) {
        //	创建map 集合
        Map<String, Object> result = new HashMap();
        //	创建一个支付金额;
        BigDecimal totalAmount = new BigDecimal("0.00");
        //	订单业务;
        if (paymentType.equals(SystemConstant.PAYMENT_TYPE_ORDER)) {
            //	属于订单，如果状态是取消订单，则不需要生成二维码！
            Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfo(orderNo);
            Assert.notNull(orderInfoResult, "订单信息结果为空！");
            OrderInfo orderInfo = orderInfoResult.getData();
            //	判断
            Assert.notNull(orderInfo, "订单信息为空！");
            if (orderInfo.getOrderStatus().equals(SystemConstant.ORDER_STATUS_CANCEL)) {
                return result;
            }
            totalAmount = orderInfo.getOrderAmount();
        } else {
            //	属于充值 recharge_info
            Result<RechargeInfo> rechargeInfoResult = rechargeInfoFeignClient.getRechargeInfo(orderNo);
            Assert.notNull(rechargeInfoResult, "充值信息结果为空！");
            RechargeInfo rechargeInfo = rechargeInfoResult.getData();
            Assert.notNull(rechargeInfo, "充值信息为空！");
            totalAmount = rechargeInfo.getRechargeAmount();
        }
        //	保存支付交易记录用来跟微信对账！ payment_info;
        paymentInfoService.savePaymentInfo(userId, paymentType, orderNo, totalAmount);
        //	创建servie 对象;
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // 跟之前下单示例一样，填充预下单参数
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        //	单位是分;
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setDescription("测试商品标题");
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        //	商户订单号(在微信服务内部使用 out_trade_no 属性来表示) out_trade_no = order_no
        //	transaction_id = out_trade_no;
        request.setOutTradeNo(orderNo);
        //	设置支付者;
        Payer payer = new Payer();
        //	获取openid；
        Result<UserInfoVo> infoVoResult = userInfoFeignClient.getUserInfo(userId);
        //	判断
        Assert.notNull(infoVoResult, "用户信息结果");
        UserInfoVo userInfoVo = infoVoResult.getData();
        Assert.notNull(userInfoVo, "用户信息不存在！");
        payer.setOpenid(userInfoVo.getWxOpenId());
        request.setPayer(payer);
        // response包含了调起支付所需的所有参数，可直接用于前端调起支付
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        //	赋值数据
        result.put("timeStamp", response.getTimeStamp()); // 时间戳
        result.put("nonceStr", response.getNonceStr());   // 随机字符串
        result.put("package", response.getPackageVal());  // 订单详情扩展字符串
        result.put("signType", response.getSignType());   // 签名方式
        result.put("paySign", response.getPaySign());     // 签名
        //	返回数据
        return result;
    }
}
